// HSS.Forms.Docking.DockPanel.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       DockPanel.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
namespace HSS.Forms.Docking
{
	#region Using Directives
	using System;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.Diagnostics.CodeAnalysis;
	using System.Drawing;
	using System.Windows.Forms;
	#endregion

	#region Delegates

	/// <summary>
	/// DeserializeDockContent IDockContent delegate
	/// </summary>
	/// <param name="persistString">string</param>
	/// <returns>IDockContent</returns>
	[SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "0#")]
	public delegate IDockContent DeserializeDockContent(string persistString);

	#endregion

	#region DockPanel
	/// <summary>
	/// A DockPanel is the control that contains all docking objects
	/// </summary>
	[Designer(typeof(System.Windows.Forms.Design.ControlDesigner))]
	[ToolboxBitmap(typeof(DockPanel), "HSS.Forms.Docking.DockPanel")]
	public partial class DockPanel : Panel
	{
		#region Events
		/// <summary>
		/// ContentAdded event
		/// </summary>
		[LocalizedCategory("Category_DockingNotification")]
		[LocalizedDescription("DockPanel_ContentAdded_Description")]
		public event EventHandler<DockContentEventArgs> ContentAdded
		{
			add { Events.AddHandler(ContentAddedEvent, value); }
			remove { Events.RemoveHandler(ContentAddedEvent, value); }
		}
		/// <summary>
		/// Fires the ContentAdded event
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnContentAdded(DockContentEventArgs e)
		{
			EventHandler<DockContentEventArgs> handler = (EventHandler<DockContentEventArgs>)Events[ContentAddedEvent];
			if (handler != null)
				handler(this, e);
		}
		/// <summary>
		/// ContentRemoved event
		/// </summary>
		[LocalizedCategory("Category_DockingNotification")]
		[LocalizedDescription("DockPanel_ContentRemoved_Description")]
		public event EventHandler<DockContentEventArgs> ContentRemoved
		{
			add { Events.AddHandler(ContentRemovedEvent, value); }
			remove { Events.RemoveHandler(ContentRemovedEvent, value); }
		}
		/// <summary>
		/// Fires the ContentRemoved event
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnContentRemoved(DockContentEventArgs e)
		{
			EventHandler<DockContentEventArgs> handler = (EventHandler<DockContentEventArgs>)Events[ContentRemovedEvent];
			if (handler != null)
				handler(this, e);
		}
		#endregion

		#region Fields

		private static readonly object ContentAddedEvent = new object();
		private static readonly object ContentRemovedEvent = new object();

		private Rectangle[] clippingRects = null;
		private SolidBrush appBrush = null;
		private bool isDisposed = false;

		#endregion

		#region Constructor
		/// <summary>
		/// Constructor
		/// </summary>
		public DockPanel()
		{
			_instance = this;

			_focusManager = new FocusManagerImpl(this);
			_extender = new DockPanelExtender(this);
			_panes = new DockPaneCollection();
			_floatWindows = new FloatWindowCollection();

			this.DoubleBuffered = true;

			SuspendLayout();

			_autoHideWindow = new AutoHideWindowControl(this);
			_autoHideWindow.Visible = false;
			SetAutoHideWindowParent();

			_dummyControl = new DummyControl();
			_dummyControl.Bounds = new Rectangle(0, 0, 1, 1);
			Controls.Add(_dummyControl);

			_dockWindows = new DockWindowCollection(this);
			Controls.AddRange(new Control[]	{
				DockWindows[DockState.Document],
				DockWindows[DockState.DockLeft],
				DockWindows[DockState.DockRight],
				DockWindows[DockState.DockTop],
				DockWindows[DockState.DockBottom]
				});

			_dummyContent = new DockContent();
			ResumeLayout();
		}
		#endregion

		#region Properties

		#region Public

		#region Appearance Category
		/// <summary>
		/// Gets or sets the AppWorkspace BackColor
		/// </summary>
		[Category("Appearance")]
		[Description("Gets or sets the AppWorkspace BackColor")]
		[DefaultValue(typeof(Color), "AppWorkspace")]
		public Color AppWorkspaceBackColor
		{
			get { return _appWorkspaceBackColor; }
			set
			{
				if (_appWorkspaceBackColor == value)
					return;

				_appWorkspaceBackColor = value;
				this.Invalidate();
			}
		} Color _appWorkspaceBackColor = SystemColors.AppWorkspace;
		/// <summary>
		/// Gets or sets the overall back color for the DockPanel areas
		/// </summary>
		[Category("Appearance")]
		[Description("Gets or sets the overall back color for the DockPanel areas")]
		[DefaultValue(typeof(Color), "239, 240, 250")]
		public Color EnvironmentBackColor
		{
			get { return _envBackColor; }
			set
			{
				if (_envBackColor == value)
					return;

				_envBackColor = value;
				this.Invalidate();
			}
		} Color _envBackColor = Color.FromArgb(239, 240, 250);
		/// <summary>
		/// Gets or sets the Document Fill Color
		/// </summary>
		[Category("Appearance")]
		[Description("Gets or sets the Document Fill Color")]
		[DefaultValue(typeof(Color), "215, 227, 240")]
		public Color DocumentFillColor
		{
			get { return _documentFillColor; }
			set
			{
				if (_documentFillColor == value)
					return;

				_documentFillColor = value;
				this.Invalidate();
			}
		} Color _documentFillColor = Color.FromArgb(215, 227, 240);
		/// <summary>
		/// Gets or sets the Document Tab Active Fill Color
		/// </summary>
		[Category("Appearance")]
		[Description("Gets or sets the Document Tab Active Fill Color")]
		[DefaultValue(typeof(Color), "215, 227, 240")]
		public Color DocumentTabActiveFillColor
		{
			get { return _documentTabActiveFillColor; }
			set
			{
				if (_documentTabActiveFillColor == value)
					return;

				_documentTabActiveFillColor = value;
				this.Invalidate();
			}
		} Color _documentTabActiveFillColor = Color.FromArgb(215, 227, 240);
		/// <summary>
		/// Gets or sets the Document Tab Inactive Fill Color
		/// </summary>
		[Category("Appearance")]
		[Description("Gets or sets the Document Tab Inactive Fill Color")]
		[DefaultValue(typeof(Color), "142, 174, 201")]
		public Color DocumentTabInactiveFillColor
		{
			get { return _documentTabInactiveFillColor; }
			set
			{
				if (_documentTabInactiveFillColor == value)
					return;

				_documentTabInactiveFillColor = value;
				this.Invalidate();
			}
		} Color _documentTabInactiveFillColor = Color.FromArgb(142, 174, 201);
		/// <summary>
		/// Gets or sets the Document Border Color
		/// </summary>
		[Category("Appearance")]
		[Description("Gets or sets the Document Border Color")]
		[DefaultValue(typeof(Color), "135, 180, 197")]
		public Color DocumentBorderColor
		{
			get { return _documentBorderColor; }
			set
			{
				if (_documentBorderColor == value)
					return;

				_documentBorderColor = value;
				this.Invalidate();
			}
		} Color _documentBorderColor = Color.FromArgb(135, 180, 197);
		/// <summary>
		/// Gets or sets the Document InnerBorder Color
		/// </summary>
		[Category("Appearance")]
		[Description("Gets or sets the Document InnerBorder Color")]
		[DefaultValue(typeof(Color), "LightSteelBlue")]
		public Color DocumentInnerBorderColor
		{
			get { return _documentInnerBorderColor; }
			set
			{
				if (_documentInnerBorderColor == value)
					return;

				_documentInnerBorderColor = value;
				this.Invalidate();
			}
		} Color _documentInnerBorderColor = Color.LightSteelBlue;
		/// <summary>
		/// Gets or sets whether or not to show a border around the Pane when Pane is Document State
		/// </summary>
		[Category("Appearance")]
		[Description("Gets or sets whether or not to show a border around the Pane when Pane is Document State")]
		[DefaultValue(true)]
		public bool ShowDocumentBoder
		{
			get { return _showDocumentBoder; }
			set
			{
				if (_showDocumentBoder == value)
					return;

				_showDocumentBoder = value;
				this.Invalidate();
			}
		} bool _showDocumentBoder = true;
		/// <summary>
		/// Gets or sets the Tool Border Color
		/// </summary>
		[Category("Appearance")]
		[Description("Gets or sets the Tool Border Color")]
		[DefaultValue(typeof(Color), "ControlDark")]
		public Color ToolBorderColor
		{
			get { return _toolBorderColor; }
			set
			{
				if (_toolBorderColor == value)
					return;

				_toolBorderColor = value;
				this.Invalidate();
			}
		} Color _toolBorderColor = SystemColors.ControlDark;
		/// <summary>
		/// RightToLeftLayout
		/// </summary>
		[DefaultValue(false)]
		[LocalizedCategory("Appearance")]
		[LocalizedDescription("DockPanel_RightToLeftLayout_Description")]
		public bool RightToLeftLayout
		{
			get { return _rightToLeftLayout; }
			set
			{
				if (_rightToLeftLayout == value)
					return;

				_rightToLeftLayout = value;
				foreach (FloatWindow floatWindow in FloatWindows)
					floatWindow.RightToLeftLayout = value;
			}
		} bool _rightToLeftLayout = false;
		#endregion

		#region Docking Category
		/// <summary>
		/// AllowEndUserDocking
		/// </summary>
		[LocalizedCategory("Category_Docking")]
		[LocalizedDescription("DockPanel_AllowEndUserDocking_Description")]
		[DefaultValue(true)]
		public bool AllowEndUserDocking
		{
			get { return _allowEndUserDocking; }
			set { _allowEndUserDocking = value; }
		} bool _allowEndUserDocking = true;
		/// <summary>
		/// AllowEndUserNestedDocking
		/// </summary>
		[LocalizedCategory("Category_Docking")]
		[LocalizedDescription("DockPanel_AllowEndUserNestedDocking_Description")]
		[DefaultValue(true)]
		public bool AllowEndUserNestedDocking
		{
			get { return _allowEndUserNestedDocking; }
			set { _allowEndUserNestedDocking = value; }
		} bool _allowEndUserNestedDocking = true;
		/// <summary>
		/// Gets or sets whether or not to show the DocumentIcon
		/// </summary>
		[DefaultValue(false)]
		[LocalizedCategory("Category_Docking")]
		[LocalizedDescription("DockPanel_ShowDocumentIcon_Description")]
		public bool ShowDocumentIcon
		{
			get { return _showDocumentIcon; }
			set
			{
				if (_showDocumentIcon == value)
					return;

				_showDocumentIcon = value;
				Refresh();
			}
		} bool _showDocumentIcon = false;
		/// <summary>
		/// Gets or sets the DockBottom portion
		/// </summary>
		[LocalizedCategory("Category_Docking")]
		[LocalizedDescription("DockPanel_DockBottomPortion_Description")]
		[DefaultValue(0.25)]
		public double DockBottomPortion
		{
			get { return _dockBottomPortion; }
			set
			{
				if (value <= 0)
					throw new ArgumentOutOfRangeException("value");

				if (value == _dockBottomPortion)
					return;

				_dockBottomPortion = value;

				if (_dockBottomPortion < 1 && _dockTopPortion < 1)
				{
					if (_dockTopPortion + _dockBottomPortion > 1)
						_dockTopPortion = 1 - _dockBottomPortion;
				}

				PerformLayout();
			}
		} double _dockBottomPortion = 0.25;
		/// <summary>
		/// Gets or sets the DockLeft portion
		/// </summary>
		[LocalizedCategory("Category_Docking")]
		[LocalizedDescription("DockPanel_DockLeftPortion_Description")]
		[DefaultValue(0.25)]
		public double DockLeftPortion
		{
			get { return _dockLeftPortion; }
			set
			{
				if (value <= 0)
					throw new ArgumentOutOfRangeException("value");

				if (value == _dockLeftPortion)
					return;

				_dockLeftPortion = value;

				if (_dockLeftPortion < 1 && _dockRightPortion < 1)
				{
					if (_dockLeftPortion + _dockRightPortion > 1)
						_dockRightPortion = 1 - _dockLeftPortion;
				}
				PerformLayout();
			}
		} double _dockLeftPortion = 0.25;
		/// <summary>
		/// Gets or sets the DockRight portion
		/// </summary>
		[LocalizedCategory("Category_Docking")]
		[LocalizedDescription("DockPanel_DockRightPortion_Description")]
		[DefaultValue(0.25)]
		public double DockRightPortion
		{
			get { return _dockRightPortion; }
			set
			{
				if (value <= 0)
					throw new ArgumentOutOfRangeException("value");

				if (value == _dockRightPortion)
					return;

				_dockRightPortion = value;

				if (_dockLeftPortion < 1 && _dockRightPortion < 1)
				{
					if (_dockLeftPortion + _dockRightPortion > 1)
						_dockLeftPortion = 1 - _dockRightPortion;
				}
				PerformLayout();
			}
		} double _dockRightPortion = 0.25;
		/// <summary>
		/// Gets or sets the DockTop portion
		/// </summary>
		[LocalizedCategory("Category_Docking")]
		[LocalizedDescription("DockPanel_DockTopPortion_Description")]
		[DefaultValue(0.25)]
		public double DockTopPortion
		{
			get { return _dockTopPortion; }
			set
			{
				if (value <= 0)
					throw new ArgumentOutOfRangeException("value");

				if (value == _dockTopPortion)
					return;

				_dockTopPortion = value;

				if (_dockTopPortion < 1 && _dockBottomPortion < 1)
				{
					if (_dockTopPortion + _dockBottomPortion > 1)
						_dockBottomPortion = 1 - _dockTopPortion;
				}
				PerformLayout();
			}
		} double _dockTopPortion = 0.25;
		/// <summary>
		/// Gets or sets the Default Docking <seealso cref="DocumentStyle"/>
		/// </summary>
		[LocalizedCategory("Category_Docking")]
		[LocalizedDescription("DockPanel_DocumentStyle_Description")]
		[DefaultValue(DocumentStyle.DockingMdi)]
		public DocumentStyle DocumentStyle
		{
			get { return _documentStyle; }
			set
			{
				if (value == _documentStyle)
					return;

				if (!Enum.IsDefined(typeof(DocumentStyle), value))
					throw new InvalidEnumArgumentException();

				if (value == DocumentStyle.SystemMdi && DockWindows[DockState.Document].VisibleNestedPanes.Count > 0)
					throw new InvalidEnumArgumentException();

				_documentStyle = value;

				SuspendLayout(true);

				SetAutoHideWindowParent();
				SetMdiClient();
				InvalidateWindowRegion();

				foreach (IDockContent content in Contents)
				{
					if (content.DockHandler.DockState == DockState.Document)
						content.DockHandler.SetPaneAndVisible(content.DockHandler.Pane);
				}

				PerformMdiClientLayout();

				ResumeLayout(true, true);
			}
		} DocumentStyle _documentStyle = DocumentStyle.DockingMdi;
		#endregion

		#region Layout Category
		/// <summary>
		/// Gets or set the Default FloatWindow size
		/// </summary>
		[Category("Layout")]
		[LocalizedDescription("DockPanel_DefaultFloatWindowSize_Description")]
		public Size DefaultFloatWindowSize
		{
			get { return _defaultFloatWindowSize; }
			set { _defaultFloatWindowSize = value; }
		} Size _defaultFloatWindowSize = new Size(300, 300);
		#endregion

		#region Non-Browsable

		/// <summary>
		/// Gets a reference to the latest DockPanel instance
		/// </summary>
		[Browsable(false)]
		public static DockPanel Instance
		{
			get { return _instance; }
		} static DockPanel _instance;

		/// <summary>
		/// ActiveAutoHideContent
		/// </summary>
		[Browsable(false)]
		public IDockContent ActiveAutoHideContent
		{
			get { return AutoHideWindow.ActiveContent; }
			set { AutoHideWindow.ActiveContent = value; }
		}

		/// <summary>
		/// Gets the DockWindows Collection
		/// </summary>
		[Browsable(false)]
		public DockWindowCollection DockWindows
		{
			get { return _dockWindows; }
		} DockWindowCollection _dockWindows;

		/// <summary>
		/// Gets the DockPanelExtender
		/// </summary>
		[Browsable(false)]
		public DockPanelExtender Extender
		{
			get { return _extender; }
		} DockPanelExtender _extender;

		/// <summary>
		/// Gets the DockPaneFactory
		/// </summary>
		[Browsable(false)]
		public DockPanelExtender.IDockPaneFactory DockPaneFactory
		{
			get { return Extender.DockPaneFactory; }
		}

		/// <summary>
		/// Gets the FloatWindowFactory
		/// </summary>
		[Browsable(false)]
		public DockPanelExtender.IFloatWindowFactory FloatWindowFactory
		{
			get { return Extender.FloatWindowFactory; }
		}

		/// <summary>
		/// Gets the DockPane Collection
		/// </summary>
		[Browsable(false)]
		public DockPaneCollection Panes
		{
			get { return _panes; }
		} DockPaneCollection _panes;

		/// <summary>
		/// Contents collection
		/// </summary>
		[Browsable(false)]
		public DockContentCollection Contents
		{
			get { return _contents; }
		} DockContentCollection _contents = new DockContentCollection();

		/// <summary>
		/// Gets the count of Document DockContents
		/// </summary>
		[Browsable(false)]
		public int DocumentsCount
		{
			get
			{
				int count = 0;
				foreach (IDockContent content in Documents)
					count++;

				return count;
			}
		}

		/// <summary>
		/// Gets all DockContents that are Documents
		/// </summary>
		[Browsable(false)]
		public IEnumerable<IDockContent> Documents
		{
			get
			{
				foreach (IDockContent content in Contents)
				{
					if (content.DockHandler.DockState == DockState.Document)
						yield return content;
				}
			}
		}

		/// <summary>
		/// Gets all Float Windows
		/// </summary>
		[Browsable(false)]
		public FloatWindowCollection FloatWindows
		{
			get { return _floatWindows; }
		} FloatWindowCollection _floatWindows;

		#endregion

		#endregion

		#region Internal
		internal DockPanelExtender.IDockPaneCaptionFactory DockPaneCaptionFactory
		{
			get { return Extender.DockPaneCaptionFactory; }
		}
		internal DockPanelExtender.IDockPaneStripFactory DockPaneStripFactory
		{
			get { return Extender.DockPaneStripFactory; }
		}
		internal DockPanelExtender.IAutoHideStripFactory AutoHideStripFactory
		{
			get { return Extender.AutoHideStripFactory; }
		}
		internal AutoHideStripBase AutoHideStripControl
		{
			get
			{
				if (_autoHideStripControl == null)
				{
					_autoHideStripControl = AutoHideStripFactory.CreateAutoHideStrip(this);
					Controls.Add(_autoHideStripControl);
				}
				return _autoHideStripControl;
			}
		} AutoHideStripBase _autoHideStripControl = null;
		internal DockContent DummyContent
		{
			get { return _dummyContent; }
		}  DockContent _dummyContent;
		internal Rectangle DocumentWindowBounds
		{
			get
			{
				Rectangle rectDocumentBounds = DisplayRectangle;
				if (DockWindows[DockState.DockLeft].Visible)
				{
					rectDocumentBounds.X += DockWindows[DockState.DockLeft].Width;
					rectDocumentBounds.Width -= DockWindows[DockState.DockLeft].Width;
				}
				if (DockWindows[DockState.DockRight].Visible)
					rectDocumentBounds.Width -= DockWindows[DockState.DockRight].Width;
				if (DockWindows[DockState.DockTop].Visible)
				{
					rectDocumentBounds.Y += DockWindows[DockState.DockTop].Height;
					rectDocumentBounds.Height -= DockWindows[DockState.DockTop].Height;
				}
				if (DockWindows[DockState.DockBottom].Visible)
					rectDocumentBounds.Height -= DockWindows[DockState.DockBottom].Height;

				return rectDocumentBounds;

			}
		}
		internal Rectangle DockArea
		{
			get
			{
				return new Rectangle(DockPadding.Left, DockPadding.Top,
					ClientRectangle.Width - DockPadding.Left - DockPadding.Right,
					ClientRectangle.Height - DockPadding.Top - DockPadding.Bottom);
			}
		}
		internal Form ParentForm
		{
			get
			{
				if (!IsParentFormValid())
					throw new InvalidOperationException(Strings.DockPanel_ParentFor_Invalid);

				return GetMdiClientController().ParentForm;
			}
		}
		#endregion

		#region Private

		private Rectangle SystemMdiClientBounds
		{
			get
			{
				if (!IsParentFormValid() || !Visible)
					return Rectangle.Empty;

				Rectangle rect = ParentForm.RectangleToClient(RectangleToScreen(DocumentWindowBounds));
				return rect;
			}
		}
		private Rectangle DocumentRectangle
		{
			get
			{
				Rectangle rect = DockArea;
				if (DockWindows[DockState.DockLeft].VisibleNestedPanes.Count != 0)
				{
					rect.X += (int)(DockArea.Width * DockLeftPortion);
					rect.Width -= (int)(DockArea.Width * DockLeftPortion);
				}
				if (DockWindows[DockState.DockRight].VisibleNestedPanes.Count != 0)
					rect.Width -= (int)(DockArea.Width * DockRightPortion);
				if (DockWindows[DockState.DockTop].VisibleNestedPanes.Count != 0)
				{
					rect.Y += (int)(DockArea.Height * DockTopPortion);
					rect.Height -= (int)(DockArea.Height * DockTopPortion);
				}
				if (DockWindows[DockState.DockBottom].VisibleNestedPanes.Count != 0)
					rect.Height -= (int)(DockArea.Height * DockBottomPortion);

				return rect;
			}
		}
		private Control DummyControl
		{
			get { return _dummyControl; }
		} Control _dummyControl;

		#endregion

		#endregion

		#region Overrides
		/// <summary>
		/// Releases the unmanaged resources used by the System.Windows.Forms.Control 
		/// and its child controls and optionally releases the managed resources
		/// </summary>
		/// <param name="disposing">true to release both managed and unmanaged 
		/// resources; false to release only unmanaged resources</param>
		protected override void Dispose(bool disposing)
		{
			lock (this)
			{
				if (!isDisposed && disposing)
				{
					_focusManager.Dispose();
					if (_mdiClientController != null)
					{
						_mdiClientController.HandleAssigned -= new EventHandler(MdiClientHandleAssigned);
						_mdiClientController.MdiChildActivate -= new EventHandler(ParentFormMdiChildActivate);
						_mdiClientController.Layout -= new LayoutEventHandler(MdiClient_Layout);
						_mdiClientController.Dispose();
					}
					FloatWindows.Dispose();
					Panes.Dispose();
					DummyContent.Dispose();

					isDisposed = true;
				}

				base.Dispose(disposing);
			}
		}
		/// <summary>
		/// Performs the layout
		/// </summary>
		/// <param name="levent">A System.Windows.Forms.LayoutEventArgs that contains the event data</param>
		protected override void OnLayout(LayoutEventArgs levent)
		{
			SuspendLayout(true);

			AutoHideStripControl.Bounds = ClientRectangle;

			CalculateDockPadding();

			DockWindows[DockState.DockLeft].Width = GetDockWindowSize(DockState.DockLeft);
			DockWindows[DockState.DockRight].Width = GetDockWindowSize(DockState.DockRight);
			DockWindows[DockState.DockTop].Height = GetDockWindowSize(DockState.DockTop);
			DockWindows[DockState.DockBottom].Height = GetDockWindowSize(DockState.DockBottom);

			AutoHideWindow.Bounds = GetAutoHideWindowBounds(AutoHideWindowRectangle);

			DockWindows[DockState.Document].BringToFront();
			AutoHideWindow.BringToFront();

			base.OnLayout(levent);

			if (DocumentStyle == DocumentStyle.SystemMdi && MdiClientExists)
			{
				SetMdiClientBounds(SystemMdiClientBounds);
				InvalidateWindowRegion();
			}
			else if (DocumentStyle == DocumentStyle.DockingMdi)
				InvalidateWindowRegion();

			ResumeLayout(true, true);
		}
		/// <summary>
		/// Raises the System.Windows.Forms.Control.Paint event and paints the Background
		/// </summary>
		/// <param name="e">A System.Windows.Forms.PaintEventArgs that contains the event data</param>
		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint(e);

			Graphics g = e.Graphics;
			if (null == appBrush)
				appBrush = new SolidBrush(this.AppWorkspaceBackColor);
			if (appBrush.Color != this.AppWorkspaceBackColor)
				appBrush.Color = this.AppWorkspaceBackColor;
			g.FillRectangle(appBrush, this.ClientRectangle);
		}
		/// <summary>
		/// Raises the System.Windows.Forms.Control.ParentChanged event
		/// </summary>
		/// <param name="e">An System.EventArgs that contains the event data</param>
		protected override void OnParentChanged(EventArgs e)
		{
			SetAutoHideWindowParent();
			GetMdiClientController().ParentForm = (this.Parent as Form);
			base.OnParentChanged(e);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		protected override void OnVisibleChanged(EventArgs e)
		{
			base.OnVisibleChanged(e);

			if (Visible)
				SetMdiClient();
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		protected override void OnRightToLeftChanged(EventArgs e)
		{
			base.OnRightToLeftChanged(e);
			foreach (FloatWindow floatWindow in FloatWindows)
			{
				if (floatWindow.RightToLeft != RightToLeft)
					floatWindow.RightToLeft = RightToLeft;
			}
		}
		#endregion

		#region Methods

		#region Public
		/// <summary>
		/// 
		/// </summary>
		/// <param name="dockStyle"></param>
		/// <param name="fullPanelEdge"></param>
		public void UpdateDockWindowZOrder(DockStyle dockStyle, bool fullPanelEdge)
		{
			if (dockStyle == DockStyle.Left)
			{
				if (fullPanelEdge)
					DockWindows[DockState.DockLeft].SendToBack();
				else
					DockWindows[DockState.DockLeft].BringToFront();
			}
			else if (dockStyle == DockStyle.Right)
			{
				if (fullPanelEdge)
					DockWindows[DockState.DockRight].SendToBack();
				else
					DockWindows[DockState.DockRight].BringToFront();
			}
			else if (dockStyle == DockStyle.Top)
			{
				if (fullPanelEdge)
					DockWindows[DockState.DockTop].SendToBack();
				else
					DockWindows[DockState.DockTop].BringToFront();
			}
			else if (dockStyle == DockStyle.Bottom)
			{
				if (fullPanelEdge)
					DockWindows[DockState.DockBottom].SendToBack();
				else
					DockWindows[DockState.DockBottom].BringToFront();
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public IDockContent[] DocumentsToArray()
		{
			int count = DocumentsCount;
			IDockContent[] documents = new IDockContent[count];
			int i = 0;
			foreach (IDockContent content in Documents)
			{
				documents[i] = content;
				i++;
			}

			return documents;
		}
		/// <summary>
		/// Determine if a document already exists by the specified name
		/// </summary>
		/// <param name="DocumentName">The name to compare</param>
		/// <returns>true if exists; otherwise false</returns>
		public bool DocumentExists(string DocumentName)
		{
			foreach (IDockContent content in Documents)
			{
				if (((DockContent)content).Text == DocumentName)
					return true;
			}

			return false;
		}
		/// <summary>
		/// Set the Pane Index
		/// </summary>
		/// <param name="pane">The pane to set</param>
		/// <param name="index">The index to set the pane to</param>
		public void SetPaneIndex(DockPane pane, int index)
		{
			int oldIndex = Panes.IndexOf(pane);
			if (oldIndex == -1)
				throw (new ArgumentException(Strings.DockPanel_SetPaneIndex_InvalidPane));

			if (index < 0 || index > Panes.Count - 1)
				if (index != -1)
					throw (new ArgumentOutOfRangeException(Strings.DockPanel_SetPaneIndex_InvalidIndex));

			if (oldIndex == index)
				return;
			if (oldIndex == Panes.Count - 1 && index == -1)
				return;

			Panes.Remove(pane);
			if (index == -1)
				Panes.Add(pane);
			else if (oldIndex < index)
				Panes.AddAt(pane, index - 1);
			else
				Panes.AddAt(pane, index);
		}
		/// <summary>
		/// Suspend the layout of the DockWindows
		/// </summary>
		/// <param name="allWindows">true for all Windows</param>
		public void SuspendLayout(bool allWindows)
		{
			FocusManager.SuspendFocusTracking();
			SuspendLayout();
			if (allWindows)
				SuspendMdiClientLayout();
		}
		/// <summary>
		/// Resume layout
		/// </summary>
		/// <param name="performLayout">true to call perform layout</param>
		/// <param name="allWindows">true to resume all windows</param>
		public void ResumeLayout(bool performLayout, bool allWindows)
		{
			FocusManager.ResumeFocusTracking();
			ResumeLayout(performLayout);
			if (allWindows)
				ResumeMdiClientLayout(performLayout);
		}
		#endregion

		#region Internal
		internal void ResetAutoHideStripControl()
		{
			if (_autoHideStripControl != null)
				_autoHideStripControl.Dispose();

			_autoHideStripControl = null;
		}
		internal Rectangle GetTabStripRectangle(DockState dockState)
		{
			return AutoHideStripControl.GetTabStripRectangle(dockState);
		}
		internal void AddContent(IDockContent content)
		{
			if (content == null)
				throw (new ArgumentNullException());

			if (!Contents.Contains(content))
			{
				Contents.Add(content);
				OnContentAdded(new DockContentEventArgs(content));
			}
		}
		internal void AddPane(DockPane pane)
		{
			if (Panes.Contains(pane))
				return;

			Panes.Add(pane);
		}
		internal void AddFloatWindow(FloatWindow floatWindow)
		{
			if (FloatWindows.Contains(floatWindow))
				return;

			FloatWindows.Add(floatWindow);
		}
		internal void RemoveContent(IDockContent content)
		{
			if (content == null)
				throw (new ArgumentNullException());

			if (Contents.Contains(content))
			{
				Contents.Remove(content);
				OnContentRemoved(new DockContentEventArgs(content));
			}
		}
		internal void RemovePane(DockPane pane)
		{
			if (!Panes.Contains(pane))
				return;

			Panes.Remove(pane);
		}
		internal void RemoveFloatWindow(FloatWindow floatWindow)
		{
			if (!FloatWindows.Contains(floatWindow))
				return;

			FloatWindows.Remove(floatWindow);
		}
		#endregion

		#region Private
		private int GetDockWindowSize(DockState dockState)
		{
			if (dockState == DockState.DockLeft || dockState == DockState.DockRight)
			{
				int width = ClientRectangle.Width - DockPadding.Left - DockPadding.Right;
				int dockLeftSize = _dockLeftPortion >= 1 ? (int)_dockLeftPortion : (int)(width * _dockLeftPortion);
				int dockRightSize = _dockRightPortion >= 1 ? (int)_dockRightPortion : (int)(width * _dockRightPortion);

				if (dockLeftSize < MeasurePane.MinSize)
					dockLeftSize = MeasurePane.MinSize;
				if (dockRightSize < MeasurePane.MinSize)
					dockRightSize = MeasurePane.MinSize;

				if (dockLeftSize + dockRightSize > width - MeasurePane.MinSize)
				{
					int adjust = (dockLeftSize + dockRightSize) - (width - MeasurePane.MinSize);
					dockLeftSize -= adjust / 2;
					dockRightSize -= adjust / 2;
				}

				return dockState == DockState.DockLeft ? dockLeftSize : dockRightSize;
			}
			else if (dockState == DockState.DockTop || dockState == DockState.DockBottom)
			{
				int height = ClientRectangle.Height - DockPadding.Top - DockPadding.Bottom;
				int dockTopSize = _dockTopPortion >= 1 ? (int)_dockTopPortion : (int)(height * _dockTopPortion);
				int dockBottomSize = _dockBottomPortion >= 1 ? (int)_dockBottomPortion : (int)(height * _dockBottomPortion);

				if (dockTopSize < MeasurePane.MinSize)
					dockTopSize = MeasurePane.MinSize;
				if (dockBottomSize < MeasurePane.MinSize)
					dockBottomSize = MeasurePane.MinSize;

				if (dockTopSize + dockBottomSize > height - MeasurePane.MinSize)
				{
					int adjust = (dockTopSize + dockBottomSize) - (height - MeasurePane.MinSize);
					dockTopSize -= adjust / 2;
					dockBottomSize -= adjust / 2;
				}

				return dockState == DockState.DockTop ? dockTopSize : dockBottomSize;
			}
			else
				return 0;
		}
		private void SetRegion(Rectangle[] clipRects)
		{
			if (!IsClipRectsChanged(clipRects))
				return;

			clippingRects = clipRects;

			if (clippingRects == null || clippingRects.GetLength(0) == 0)
				Region = null;
			else
			{
				Region region = new Region(new Rectangle(0, 0, this.Width, this.Height));
				foreach (Rectangle rect in clippingRects)
					region.Exclude(rect);
				Region = region;
			}
		}
		private bool IsClipRectsChanged(Rectangle[] clipRects)
		{
			if (clipRects == null && clippingRects == null)
				return false;
			else if ((clipRects == null) != (clippingRects == null))
				return true;

			foreach (Rectangle rect in clipRects)
			{
				bool matched = false;
				foreach (Rectangle rect2 in clippingRects)
				{
					if (rect == rect2)
					{
						matched = true;
						break;
					}
				}
				if (!matched)
					return true;
			}

			foreach (Rectangle rect2 in clippingRects)
			{
				bool matched = false;
				foreach (Rectangle rect in clipRects)
				{
					if (rect == rect2)
					{
						matched = true;
						break;
					}
				}
				if (!matched)
					return true;
			}
			return false;
		}
		private void CalculateDockPadding()
		{
			DockPadding.All = 0;

			int height = AutoHideStripControl.MeasureHeight();

			if (AutoHideStripControl.GetNumberOfPanes(DockState.DockLeftAutoHide) > 0)
				DockPadding.Left = height;

			if (AutoHideStripControl.GetNumberOfPanes(DockState.DockRightAutoHide) > 0)
				DockPadding.Right = height;

			if (AutoHideStripControl.GetNumberOfPanes(DockState.DockTopAutoHide) > 0)
				DockPadding.Top = height;

			if (AutoHideStripControl.GetNumberOfPanes(DockState.DockBottomAutoHide) > 0)
				DockPadding.Bottom = height;

		}
		private bool IsParentFormValid()
		{
			if (DocumentStyle == DocumentStyle.DockingSdi || DocumentStyle == DocumentStyle.DockingWindow)
				return true;

			if (!MdiClientExists)
				GetMdiClientController().RenewMdiClient();

			return (MdiClientExists);
		}
		private void SetAutoHideWindowParent()
		{
			Control parent;
			if (DocumentStyle == DocumentStyle.DockingMdi ||
				DocumentStyle == DocumentStyle.SystemMdi)
				parent = this.Parent;
			else
				parent = this;
			if (AutoHideWindow.Parent != parent)
			{
				AutoHideWindow.Parent = parent;
				AutoHideWindow.BringToFront();
			}
		}
		private void InvalidateWindowRegion()
		{
			if (DesignMode)
				return;

			DummyControl.Paint += DummyControl_Paint;
			DummyControl.Invalidate();
		}
		private void UpdateWindowRegion()
		{
			if (this.DocumentStyle == DocumentStyle.DockingMdi)
				UpdateWindowRegion_ClipContent();
			else if (this.DocumentStyle == DocumentStyle.DockingSdi ||
				this.DocumentStyle == DocumentStyle.DockingWindow)
				UpdateWindowRegion_FullDocumentArea();
			else if (this.DocumentStyle == DocumentStyle.SystemMdi)
				UpdateWindowRegion_EmptyDocumentArea();
		}
		private void UpdateWindowRegion_FullDocumentArea()
		{
			SetRegion(null);
		}
		private void UpdateWindowRegion_EmptyDocumentArea()
		{
			Rectangle rect = DocumentWindowBounds;
			SetRegion(new Rectangle[] { rect });
		}
		private void UpdateWindowRegion_ClipContent()
		{
			int count = 0;
			foreach (DockPane pane in this.Panes)
			{
				if (!pane.Visible || pane.DockState != DockState.Document)
					continue;

				count++;
			}

			if (count == 0)
			{
				SetRegion(null);
				return;
			}

			Rectangle[] rects = new Rectangle[count];
			int i = 0;
			foreach (DockPane pane in this.Panes)
			{
				if (!pane.Visible || pane.DockState != DockState.Document)
					continue;

				rects[i] = RectangleToClient(pane.RectangleToScreen(pane.ContentRectangle));
				i++;
			}

			SetRegion(rects);
		}
		private bool ShouldSerializeDefaultFloatWindowSize()
		{
			return DefaultFloatWindowSize != new Size(300, 300);
		}
		#endregion

		#endregion

		#region Event Handlers
		void MdiClientHandleAssigned(object sender, EventArgs e)
		{
			SetMdiClient();
			PerformLayout();
		}
		void MdiClient_Layout(object sender, LayoutEventArgs e)
		{
			if (DocumentStyle != DocumentStyle.DockingMdi)
				return;

			foreach (DockPane pane in Panes)
				if (pane.DockState == DockState.Document)
					pane.SetContentBounds();

			InvalidateWindowRegion();
		}
		void DummyControl_Paint(object sender, PaintEventArgs e)
		{
			DummyControl.Paint -= DummyControl_Paint;
			UpdateWindowRegion();
		}
		#endregion
	}
	#endregion
}